package study

import (
	"fmt"
	"unsafe"
)

func Operator() {
	// 运算符: 一种特殊的符号; 表示数据的运算, 赋值和比较等
	// --------------------------------------------------- 运算符优先级 ---------------------------------------------------
	// 1.运算符优先级: 表达式中运算符的执行顺序
	// 2.单目运算符, 赋值运算符从右向左运算
	// 3.大致执行顺序
	//    分类                            描述                                      在表达式中的执行顺序
	//    后缀(优先级最高)                {} [] -> . ++ --                          左到右
	//    单目                            + - ! ~ (type) * & sizeof                 右到左
	//    乘除                            * \ %                                     左到右
	//    加减                            + -                                       左到右
	//    移位                            >> <<                                     左到右
	//    关系                            > < <= >=                                 左到右
	//    相等                            == !=                                     左到右
	//    位运算                          & | ^                                     左到右
	//    逻辑运算                        && || !                                   左到右
	//    赋值运算                        = += -= *= /= <<= >>= &= |= ^=            右到左
	//    逗号(优先级最低)                ,                                         左到右

	// --------------------------------------------------- 1.算术运算符 ---------------------------------------------------
	// +(正), -(负), +, -, *, /, %(取余/取模), ++(自加), --(自减), +(字符串相加)
	// 1./: 整数相除, 结果舍弃小数部分, 取整数部分; 浮点数参与运算, 保留小数部分;
	// 2.%: a % b == a - a / b * b
	// ------------------------------ ++ 和 -- 在 golang 中不是算术运算符 ------------------------------
	// 3.go 的 ++, -- 只能单独使用(即: 只能 i++, i--, 不能 a = i++, a = i--)
	// 4.go 的 ++, -- 只能卸载变量的后面(即: 只有 i++, i--)
	fmt.Println("--------------------------------------------------- 算术运算符 ---------------------------------------------------")
	i1 := 10
	fmt.Printf("i1=%v\n", i1)
	// 参与运算的是两个整数, 相除取整数部分
	fmt.Printf("10/4=%v\n", 10/4)
	// 有浮点数参与运算, 才会保留小数部分
	fmt.Printf("10/4.0=%v\n", 10/4.0)
	// 取模运算 // a%b == a-a/b*b
	fmt.Printf("10%%4=%v\n", 10%4) // 10-10/4*4
	fmt.Printf("(-10)%%(-4)=%v\n", -10%-4)
	// 自增和自减运算
	i1++
	fmt.Printf("i1++; i1=%v\n", i1)
	i1--
	fmt.Printf("i1--; i1=%v\n", i1)
	fmt.Printf("97/7=%v; 97%%7=%v\n", 97/7, 97%7)
	F := 136.
	fmt.Printf("F=%v; 5.0/9*(F-100)=%v\n", F, 5.0/9*(F-100))

	// --------------------------------------------------- 2.赋值运算符 ---------------------------------------------------
	// =, +=, -=, *=, /=, %=
	// <<=(左移后赋值), >>=(右移后赋值), &=(按位与后赋值), |=(按位或后赋值), ^=(按位异或后赋值)
	// 1.赋值运算符执行顺序: 从右往左
	// 2.赋值运算符左边只能是变量; 右边可以是变量, 表达式, 常量
	// 3.复合赋值运算符: a += 12 <==> a = a + 12 (其他复合赋值运算符同理)
	fmt.Println("--------------------------------------------------- 赋值运算符 ---------------------------------------------------")
	i2 := 10
	fmt.Printf("执行a += 12 前; a=%v\n", i2)
	i2 += 12
	fmt.Printf("执行a += 12 后; a=%v\n", i2)
	i2 -= 12
	fmt.Printf("执行a -= 12 后; a=%v\n", i2)

	// --------------------------------------------------- 3.比较/关系运算符 ---------------------------------------------------
	// ==(等于), !=()不等于, <(小于), >(大于), <=(小于等于), >=(大于等于)
	// 1.关系运算符的结果都是 bool 型
	// 2.关系表达式经常用在 if 结构中或 for 循环结构的条件中
	fmt.Println("--------------------------------------------------- 比较/关系运算符 ---------------------------------------------------")
	fmt.Printf("1<2 的 type: %T; 1<2 的 值: %v\n", 1 < 2, 1 < 2)

	// --------------------------------------------------- 4.逻辑运算符 ---------------------------------------------------
	// &&(与), ||(或), !(非)
	// 1.通常用于连接多个条件, 返回 bool 值
	fmt.Println("--------------------------------------------------- 逻辑运算符 ---------------------------------------------------")
	fmt.Printf("true && false=%v\n", true && false)
	fmt.Printf("true || false=%v\n", true || false)
	fmt.Printf("!false=%v\n", !false)

	// --------------------------------------------------- 5.位运算符 ---------------------------------------------------
	// 位运算中以补码方式进行运算(运算出的结果是补码, 要再转成原码)
	// &(与)
	// |(或)
	// ^(异或)
	// <<(左移: 将运算符左边数的二进制位整体向左移动 n 位; 相当于乘以 2 的 n 次方; 符号位不变, 低位补 0)
	// >>(右移: 将运算符左边数的二进制位整体向右移动 n 位; 相当于除以 2 的 n 次方; 低位溢出, 符号位不变, 并用符号位补溢出)
	//   -1>>2 // 1001(原) => 1110(反) => 1111(补) => 1111(补) >> 2 = 1111(补) => 1110(反) => 1001(原) = -1

	// --------------------------------------------------- 原码, 反码, 补码 ---------------------------------------------------
	// 1.对于有符号数而言, 最高位是符号位, 0 表示整数, 1 表示负数
	// 2.正数的原码, 反码, 补码都一样
	// 3.负数的反码 = 原码按位取反(符号位不变)
	// 4.负数的补码 = 反码 + 1
	// 5.0 的反码, 补码都是 0
	// 6.计算机以补码方式进行运算(减法以加法运算, 乘除以位移方式运算)
	// 原码         反码         补码
	// 00000000 => 00000000 => 00000000 // 0
	// 00010001 => 00010001 => 00010001 // 正数
	// 10010001 => 11101110 => 11101111 // 负数
	fmt.Println("--------------------------------------------------- 位运算符 ---------------------------------------------------")
	fmt.Printf("1&3=%v\n", 1&3)     // 01 & 11 = 01
	fmt.Printf("1|2=%v\n", 1^2)     // 01 | 10 = 11
	fmt.Printf("-1^2=%v\n", -1^2)   // 10000001(原) => 11111110(反) => 11111111(补) => 11111111(补) ^ 00000010(补) = 11111101(补) => 11111100(反) => 10000011(原) = -3
	fmt.Printf("1>>2=%v\n", 1>>2)   // 1 >> 2 = 00.1
	fmt.Printf("-1>>2=%v\n", -1>>2) // 1001(原) => 1110(反) => 1111(补) => 1111(补) >> 2 = 1111(补) => 1110(反) => 1001(原) = -1
	fmt.Printf("1<<2=%v\n", 1<<2)   // 1 << 2 = 100

	// --------------------------------------------------- 6.其他运算符 ---------------------------------------------------
	// &(取变量地址), *(指针取值)
	// go 不支持三元运算符(仅支持 if else)
	fmt.Println("--------------------------------------------------- 其他运算符 ---------------------------------------------------")
	f := 10.1
	p := &f
	// &*p = p = *&p
	fmt.Printf("sizeof(f)=%v; f=%v\n", unsafe.Sizeof(f), f)
	fmt.Printf("sizeof(&f)=%v; &f=%v\n", unsafe.Sizeof(&f), &f)
	fmt.Printf("sizeof(p)=%v; p=%v\n", unsafe.Sizeof(p), p)
	fmt.Printf("sizeof(&p)=%v; &p=%v\n", unsafe.Sizeof(&p), &p)
	fmt.Printf("sizeof(*p)=%v; *p=%v\n", unsafe.Sizeof(*p), *p)
	fmt.Printf("sizeof(&p)=%v; &p=%v\n", unsafe.Sizeof(&p), &p)
	if *p == f {
		fmt.Printf("*p == f\n")
	} else {
		fmt.Printf("*p != f\n")
	}

	// --------------------------------------------------- 测试题 ---------------------------------------------------
	// 1.不使用第三个变量的情况下, 交换两个变量的值
	fmt.Println("--------------------------------------------------- 测试题 ---------------------------------------------------")
	a := 5
	b := 15
	fmt.Printf("a=%v; b=%v\n", a, b)
	a = a + b
	b = a - b // 此时 a = 原始 a + 原始 b
	a = a - b // 此时右侧的 a = 原始 a + 原始 b; b = 原始 a
	fmt.Printf("a=%v; b=%v\n", a, b)
	a = a * b
	b = a / b // 此时 a = 原始 a * 原始 b
	a = a / b // 此时右侧的 a = 原始 a * 原始 b; b = 原始 a
	fmt.Printf("a=%v; b=%v\n", a, b)
	a = a ^ b
	b = a ^ b // 此时 a = 原始 a ^ 原始 b
	a = a ^ b // 此时右侧的 a = 原始 a ^ 原始 b; b = 原始 a
	fmt.Printf("a=%v; b=%v\n", a, b)
	// 2.求三个数的最大值
	n1 := 12
	n2 := 11
	n3 := 13
	fmt.Printf("n1=%v; n2=%v; n3=%v\n", n1, n2, n3)
	if n1 > n2 {
		fmt.Printf("n1 和 n2 的最大值: %v\n", n1)
	} else {
		fmt.Printf("n1 和 n2 的最大值: %v\n", n2)
	}
}
